﻿using System;
using Runtime.Services.Battle.Entity;
using Runtime.Services.BattleAttack;
using UnityEngine;

namespace Runtime.Services.Battle.Behaviour {

    /// <summary>
    /// 子弹飞行行为
    /// </summary>
    public interface IDFR_BattleBehaviour_Fly : IDFR_BattleBehaviour {

        /// <summary>
        /// 实体
        /// </summary>
        new public interface IEntity : IDFR_BattleBehaviour.IEntity {

            /// <summary>
            /// 攻击时的快照
            /// </summary>
            IDFR_BattleAttackSnapshot AttackSnapshot { get; }

            /// <summary>
            /// 目标实体ID
            /// </summary>
            DFR_BattleEntityInstanceID TargetEntityInstanceID { get; }

            /// <summary>
            /// 开始时的地图位置
            /// </summary>
            DFR_BattleMapPosition StartMapPosition { get; }

            /// <summary>
            /// 目标地图位置提供者
            /// </summary>
            IDFR_BattleMapPositionProvider EndMapPositionProvider { get; }

            /// <summary>
            /// 目标位置提供者
            /// </summary>
            IDFR_BattleLocalPositionProvider EndLocalPositionProvider { get; }

            /// <summary>
            /// 飞行速度
            /// </summary>
            F64 FlySpeed { get; }

            /// <summary>
            /// 当前逻辑分量
            /// </summary>
            F64 CurrentLogicInterpolation { get; set; }

            /// <summary>
            /// 上一逻辑帧分量
            /// </summary>
            F64 LastLogicInterpolation { get; set; }

            /// <summary>
            /// 显示分量
            /// </summary>
            float Interpolation { get; set; }
        }

        public sealed class Info : DFR_BattleBehaviourInfo {
            public float FromInterpolation;
            public float ToInterpolation;
        }
    }

    [Implement(typeof(IDFR_BattleBehaviour_Fly))]
    internal sealed class DFR_BattleBehaviour_Fly : DFR_BattleBehaviour<IDFR_BattleBehaviour_Fly.Info>, IDFR_BattleBehaviour_Fly {

        new private IDFR_BattleBehaviour_Fly.IEntity Entity => (IDFR_BattleBehaviour_Fly.IEntity)base.Entity;

        private DFR_BattleMapPosition m_MapPosition;
        private DFR_BattleMapPosition m_LastMapPosition;

        private DFR_BattleMapPosition m_lastEndMapPosition;

        private bool m_EndImmediate;

        private DFR_BattleMapPosition m_PropEndMapPosition;
        //private Vector2F64 m_PropEndRenderOffset;

        private F64 m_FlySpeed;

        private bool m_IsExpire; // 如果超出可命中数后为true

        protected override void Release() {
            m_MapPosition = m_LastMapPosition = m_lastEndMapPosition = m_PropEndMapPosition = default;
            //m_PropEndRenderOffset = default;
            m_EndImmediate = false;
            m_FlySpeed = F64.Zero;
            m_IsExpire = false;
            base.Release();
        }

        protected override void Initialize() {
            m_MapPosition = m_LastMapPosition = Entity.StartMapPosition;
            var halfFlySpeed = Entity.FlySpeed * F64.Half;
            if (halfFlySpeed < F64.One) {
                halfFlySpeed = F64.One;
            }
            var logFlySpeed = F64.Log2Fastest(halfFlySpeed);
            m_FlySpeed = F64.Two + logFlySpeed;

            if (Entity.AttackSnapshot.Hit.Type == DFR_BattleAttackType.Prop) {
                var moveSpeed = F64.Max(Entity.EndMapPositionProvider.MoveSpeed, F64.From(0.01f));
                m_PropEndMapPosition = PredictImpactPoint(Entity.StartMapPosition, t => Entity.EndMapPositionProvider.SupposeMove(t), moveSpeed, m_FlySpeed);
                //m_PropEndMapPosition = m_Entity.EndMapPositionProvider.MapPosition;
                var direction = (Vector2F64)m_PropEndMapPosition - Entity.AttackSnapshot.LaunchMapPosition;
                var normalized = Vector2F64.Normalize(direction);
                var vector = normalized * F64.From(20);
                m_PropEndMapPosition += vector;
                //m_PropEndRenderOffset = Entity.EndMapPositionProvider.RenderOffset;
            }
        }

        protected override IDFR_BattleBehaviour_Fly.Info LogicFrame() {
            var startMapPosition = Entity.StartMapPosition;
            var endMapPosition = Entity.EndMapPositionProvider.MapPosition;
            if (Entity.FlySpeed <= F64.Zero || m_IsExpire) {
                Entity.CurrentLogicInterpolation = F64.One;
            } else {
                var flySpeedDelta = Delta(m_FlySpeed);
                DFR_BattleMapPosition lastEndMapPosition;
                if (Entity.AttackSnapshot.Hit.Type == DFR_BattleAttackType.Prop) {
                    lastEndMapPosition = m_PropEndMapPosition;
                    endMapPosition = m_PropEndMapPosition;
                } else {
                    lastEndMapPosition = Entity.CurrentLogicInterpolation == F64.Zero ? endMapPosition : m_lastEndMapPosition;
                }
                var lastMapPosition = Vector2F64.Lerp(startMapPosition, lastEndMapPosition, Entity.CurrentLogicInterpolation);
                var distance = Vector2F64.Distance(startMapPosition, lastMapPosition);
                distance += flySpeedDelta;
                var length = Vector2F64.Distance(Entity.StartMapPosition, endMapPosition);
                var interpolation = distance / length;
                if (interpolation > F64.One) {
                    interpolation = F64.One;
                }
                Entity.CurrentLogicInterpolation = interpolation;
            }

            if (Entity.LastLogicInterpolation == F64.Zero && Entity.CurrentLogicInterpolation == F64.One) {
                m_EndImmediate = true;
            }

            m_LastMapPosition = m_MapPosition;
            m_lastEndMapPosition = endMapPosition;
            m_MapPosition = Vector2F64.Lerp(startMapPosition, endMapPosition, Entity.CurrentLogicInterpolation);
            if (!m_IsExpire) {
                m_IsExpire = BattleAttackService.Instance.Through(Entity.AttackSnapshot, Entity.TargetEntityInstanceID, m_LastMapPosition, m_MapPosition, endMapPosition,
                    sourceModelDictionary: DFR_BattleBase.DataCenter.Models.AttackSourceDictionary,
                    targetModelDictionary: DFR_BattleBase.DataCenter.Models.AttackTargetDictionary);
            }
            var info = new IDFR_BattleBehaviour_Fly.Info {
                Type = DFR_BattleBehaviourType.Fly,
            };
            info.FromInterpolation = Entity.LastLogicInterpolation.Float;
            info.ToInterpolation = Entity.CurrentLogicInterpolation.Float;
            Entity.LastLogicInterpolation = Entity.CurrentLogicInterpolation;
            return info;
        }

        protected override void Execute(IDFR_BattleBehaviour_Fly.Info info) {
        }

        protected override void Update(IDFR_BattleBehaviour_Fly.Info info, float interpolation) {
            StateMachine.State = DFR_BattleEntityState.Idle;

            float now;
            if (Entity.FlySpeed <= F64.Zero || m_EndImmediate) {
                Entity.Interpolation = now = 1f;
            } else {
                now = Mathf.Lerp(info.FromInterpolation, info.ToInterpolation, interpolation);
                now = Mathf.Clamp01(now);
                Entity.Interpolation = now;
            }

            Vector3 endLocalPosition;
            if (Entity.AttackSnapshot.Hit.Type == DFR_BattleAttackType.Prop) {
                //var offset = BattleServiceBase.Instance.GetRenderOffsetVector(m_PropEndRenderOffset);
                //endLocalPosition = BattleServiceBase.Instance.GetLocalPosition(m_PropEndMapPosition) + offset;
                endLocalPosition = BattleServiceBase.Instance.GetLocalPosition(m_PropEndMapPosition);
            } else {
                endLocalPosition = Entity.EndLocalPositionProvider.LocalPosition;
            }
            var lastLocalPosition = Transform.localPosition;
            endLocalPosition.z = lastLocalPosition.z;
            var startLocalPosition = BattleServiceBase.Instance.GetLocalPosition(new Vector3(Entity.StartMapPosition.X.Float, Entity.StartMapPosition.Y.Float, Transform.localPosition.z));
            var nowLocalPosition = Vector3.Lerp(startLocalPosition, endLocalPosition, now);
            Transform.localPosition = nowLocalPosition;

            // 瞄准角度变更
            var direction = nowLocalPosition - lastLocalPosition;
            if (direction != Vector3.zero) {
                float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
                if (angle < 0f) {
                    angle += 360f;
                }
                Transform.eulerAngles = new Vector3(0f, 0f, angle - 180f); // 特效多转了180;
            }
        }

        // 计算两点之间的距离平方
        private static F64 DistanceSquared(Vector2F64 a, Vector2F64 b) {
            var dx = a.X - b.X;
            var dy = a.Y - b.Y;
            return dx * dx + dy * dy;
        }

        // 计算点积
        public static F64 Dot(Vector2F64 a, Vector2F64 b) {
            return a.X * b.X + a.Y * b.Y;
        }

        // 预判子弹落点
        static Vector2F64 PredictImpactPoint(Vector2F64 startPosition, Func<F64, Vector2F64> targetPath, F64 targetSpeed, F64 bulletSpeed) {
            // 初始猜测时间
            var T = F64.One;
            // 迭代求解时间 T
            for (var i = 0; i < 100; i++) { // 最多迭代 100 次
                // 目标在时间 T 的位置
                var targetPosition = targetPath.Invoke(T);
                // 子弹飞行距离
                var bulletDistance = bulletSpeed * T;
                // 目标移动距离
                var targetDistance = targetSpeed * T;
                // 计算函数 f(T) = bulletDistance^2 - distance^2
                var fT = bulletDistance * bulletDistance - DistanceSquared(startPosition, targetPosition);
                // 计算导数 f'(T)
                var dfT = 2 * bulletSpeed * bulletSpeed * T - 2 * Dot(targetPosition - startPosition, new Vector2F64(targetSpeed, F64.Zero));
                // 更新 T
                T -= fT / dfT;
                // 如果 T 的变化很小，停止迭代
                if (F64.Abs(fT) <= F64.From(0.05f))
                    break;
            }
            // 返回预判落点
            return targetPath(T);
        }
    }
}
